﻿using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SCM.Common;
using SCM.Model.DBEntity;
using SCM.Model.Enums;
using SCM.Servie.IBusiness;
using System;
using System.IO;
using System.Reflection;

namespace SCM.WebAPI.Filter
{
    /// <summary>
    /// Http返回异常过滤器
    /// </summary>
    public class HttpResponseExceptionFilter : IActionFilter, IOrderedFilter
    {
        /// <summary>
        /// 顺序
        /// </summary>
        public int Order { get; set; } = int.MaxValue - 10;

        /// <summary>
        /// 执行调用时
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context) { }

        /// <summary>
        /// 执行调用后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            if (context.Exception is SCMException re)
            {
                HandleException(context, re);
                context.ExceptionHandled = true;
                return;
            }

            if (context.Exception is BusinessException be)
            {
                HandleBusinessException(context, be);
                context.ExceptionHandled = true;

                return;
            }
            if (context.Exception != null)
            {
                GeneralExceptionHandle(context, context.Exception);
                context.ExceptionHandled = true;
            }
        }

        private void GeneralExceptionHandle(ActionExecutedContext context, Exception e)
        {
            ViewDataPack<object> viewData = new ViewDataPack<object>();
            viewData.Code = ResultCode.Error;
            viewData.Message = e.Message;
            viewData.Data = null;

            var logerService = ServiceLocator.Instance.GetService<ILogService>();
            var model = new T_ErrorLog();
            model.ID = Guid.NewGuid().ToString("N");
            model.Source = Assembly.GetExecutingAssembly().GetName().Name;
            model.ClientIP = context.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            model.Message = e.Message;
            model.CreateTime = DateTime.Now;
            model.ProcessFlag = ProcessFlagEnum.WaitHandle;
            using (var reader = new StreamReader(context.HttpContext.Request.Body))
            {
                reader.BaseStream.Position = 0;
                model.RequestData = reader.ReadToEnd();
            }
            model.RequestUrl = context.HttpContext.Request.GetDisplayUrl();
            model.UserName = context.HttpContext?.User?.Identity?.Name;
            model.StackTrace = e.StackTrace;
            logerService.AddErrorLog(model);

            ILogger logger = ServiceLocator.Instance.GetRequiredService<ILogger<HttpResponseExceptionFilter>>();
            logger.LogError(e, e.Message);
            context.Result = new JsonResult(viewData);
        }
        private void HandleBusinessException(ActionExecutedContext context, BusinessException e)
        {
            ViewDataPack<object> viewData = new ViewDataPack<object>();
            context.HttpContext.Response.StatusCode = 200;
            viewData.Code = e.ResultCode;
            viewData.Message = e.Message;
            viewData.Data = null;
            var logerService = ServiceLocator.Instance.GetService<ILogService>();

            var model = new T_BusinessExceptionLog();
            model.ID = Guid.NewGuid().ToString("N");
            model.ClientIP = context.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
            model.Content = e.Message;
            model.ProcessFlag = ProcessFlagEnum.WaitHandle;
            model.RequestData = e.RequestData;
            model.CreateTime = DateTime.Now;
            model.RequestUrl = context.HttpContext.Request.GetDisplayUrl();
            model.UserName = context.HttpContext?.User?.Identity?.Name;
            logerService.AddBusinessLog(model);

            ILogger logger = ServiceLocator.Instance.GetRequiredService<ILogger<HttpResponseExceptionFilter>>();
            logger.LogError(e, e.Message);
            context.Result = new JsonResult(viewData);
        }
        private void HandleException(ActionExecutedContext context, SCMException e)
        {
            context.HttpContext.Response.StatusCode = (int)e.HttpStatusCode;
            context.HttpContext.Response.ContentType = "text/json;charset=utf-8;";
            ViewDataPack<object> viewData = new ViewDataPack<object>();
            viewData.Code = e.ResultCode;
            viewData.Message = e.Message;
            viewData.Data = e.Context;
            if (e.IsWriteLog)
            {
                ILogger logger = ServiceLocator.Instance.GetRequiredService<ILogger<HttpResponseExceptionFilter>>();
                logger.LogError(e, e.Message);
            }
            context.Result = new JsonResult(viewData);
        }
    }
}
